package anatex.kea.genex;

import anatex.domain.*;

import java.text.*;
import java.util.*;

import anatex.kea.AbstractAlgo;
import anatex.kea.KeywordExtractorAlgoException;
import anatex.kea.genex.extractor.*;
import anatex.domain.Document;
import anatex.kea.genex.extractor.*;

public class Extractor {

	protected Parameters parameters;
	protected Document documentText;
	protected ArrayList<String> words = null;
	protected Stemmer stemmer = null;
	protected Double fitness;
	protected StemPhraseSuffix stemPhraseSuffix;
	TreeSet<Object[]> ts = null;
	
	public Extractor() throws KeywordExtractorAlgoException {
		
		parameters = new Parameters();
		
		stemPhraseSuffix = new StemPhraseSuffix("", parameters);
		
		clear();
	}
	
	public Extractor(Parameters p) throws KeywordExtractorAlgoException {
		parameters = p;
		
		stemPhraseSuffix = new StemPhraseSuffix("", parameters);
		
		clear();
	}
	
	public Extractor(Parameters p, Document dt) throws KeywordExtractorAlgoException {
		parameters = p;
		documentText = dt;
		
		stemPhraseSuffix = new StemPhraseSuffix(documentText.getContent(), parameters);
		
		clear();
	}

	protected void clear() {
		words = new ArrayList<String>();
	}
	
	protected void extractWords() {
		if (words.size() > 0) {
			return;
		}
		
		int wc = 0;
		String content = documentText.getContent();
		BreakIterator it = BreakIterator.getWordInstance(GenEx.getCurrentLocale());
		
		it.setText(content);
		int start = it.first();
		int end = it.next();
		
		while (BreakIterator.DONE != end) {
			String word = content.substring(start, end);
			if (Character.isLetterOrDigit(word.charAt(0))) {
				words.add(word);
				wc ++;
			}
			
			start = end;
			end = it.next();
		}
	}
	
	protected TreeSet<Object[]> suffixTopStemPhrases(TreeSet<Object[]> ts) {
		TreeSet<Object[]> suffixed = new TreeSet<Object[]>(Assessor.cmp);
		TreeSet<String> tsIndex = new TreeSet<String>();

		stemPhraseSuffix.setCustomLocale(documentText.getCustomLocale());
		
		Iterator<Object[]> it = ts.iterator();
		
		while (it.hasNext()) {
			Object[] item = it.next();
			String phrase = stemPhraseSuffix.getBestSuffix((String)item[0]);
			
			if ("" != phrase && ! tsIndex.contains(phrase)) {
				suffixed.add(new Object[] {phrase, (Double)item[1]});
				
				tsIndex.add(phrase);
			}
		}
		
		return suffixed;
	}
	
	/**
	 * Modifies the given phrase set
	 * @param ts
	 */
	protected void finalizeOutput (TreeSet<Object[]> ts) {
		//TODO Find out why and how ts can be empty...
		if (0 == ts.size()) {
			return;
		}
		
		fitness = 0.0;
		int pLengthSum = 0;
		int pAvgLength = 0;
		Double MIN_LENGTH_LOW_RANK = (Double)parameters.get(Parameters.MIN_LENGTH_LOW_RANK);
		int MIN_RANK_LOW_LENGTH = (Integer)parameters.get(Parameters.MIN_RANK_LOW_LENGTH);
		
		Iterator<Object[]> it = ts.iterator();
		
		while (it.hasNext()) {
			Object[] item = it.next();
			
			pLengthSum += ((String)item[0]).length();
		}
		
		pAvgLength = new Double(Math.floor(pLengthSum / ts.size())).intValue();
		
		it = ts.iterator();
		
		int counter = 0;
		while (it.hasNext()) {
			Object[] item = it.next();
			counter ++;
			
			int phraseLength = ((String)item[0]).length();
			
			if ((phraseLength / pAvgLength) < MIN_LENGTH_LOW_RANK) {
				if (counter <= MIN_RANK_LOW_LENGTH) {
					//TODO Implement full step 10 form the Extractor algo - must check if phrase is an abbreviation
					it.remove();
					
					continue;
				}
			}
			
			fitness += (Double)item[1];
		}
		
		if (ts.size() > 0) { 
			fitness = fitness / ts.size();
		} else {
			fitness = 0.0;
		}
	}
	
	public void setParameters(Parameters p) {
		
		parameters = p;
		
		stemPhraseSuffix.setParameters(parameters);
	}
	
	public void setDocumentText(Document dt) {
		
		documentText = dt;
		
		stemPhraseSuffix.setText(documentText.getContent());
		
		clear();
	}
	
	public Document getDocumentText () {
		return documentText;
	}
	
	public ArrayList<String> getStems() {
		
		if (null == stemmer) {
			stemmer = new Stemmer(words, parameters, documentText.getCustomLocale());
		}
		
		return stemmer.getStems();
	}
	
	public Double getFitness() {
		return new Double(fitness);
	}
	
	public void extract() {
		
		extractWords();
		
		Assessor a = new Assessor(documentText.getContent(), parameters);
		ts = a.getTopSingleStems(getStems());

		ts = a.getTopStemPhrases(stemmer.getStemPhrases(documentText.getContent().toLowerCase()));
		
		ts = suffixTopStemPhrases(ts);
		finalizeOutput(ts);
		
		Iterator<Object[]> it = ts.iterator();
		
		while(it.hasNext()) {
			Object[] i = it.next();
			
//			System.out.println(i[0] + ": " + i[1]);
		}
		
		if (ts.size() < (Integer) parameters.get(Parameters.NUM_PHRASES)) {
			fitness = 0.0;
		}
	}
	
	public TreeSet<Object[]> getExtractedKeyPhrases () {
		return ts;
	}
	
}
